const jwt = require('jsonwebtoken')
const redis = require('../redis/redisClient.js')
const ApiRequestUtil = require('../../util/ApiResponseUtil.js')

// sockets/chitchat.js
module.exports = (io) => {
    // 用于存储 用户ID -> socket.id 的映射
    const userSocketMap = new Map(); // key: uid, value: socket.id
    // 反向存储 socket.id -> 用户ID 的映射
    const socketUserMap = new Map(); // key: socket.id, value: uid
    // 用于存储 socket.id -> 用户信息 的映射
    const userDecodedMap = new Map() // key: socket.id, value: decoded

    // 查询目标用户 tid 对应的 socket.id
    function findTargetSocketId(tid) {
        return userSocketMap.get(tid) || null
    }

    io.on('connection', (socket) => {
        // console.log(`✅ Socket.io-client 客户端连接成功：${socket.id}`);

        // 客户端认证：验证用户身份信息
        socket.on('user join', (token) => {
            try {
                const decoded = jwt.verify(token, process.env.SECRET_KEY);
                userSocketMap.set(decoded.id, socket.id)
                socketUserMap.set(socket.id, decoded.id)
                userDecodedMap.set(socket.id, decoded)
                socket.emit('pass certification', ApiRequestUtil.success(200, '客户端认证通过！', userSocketMap.get(decoded.id)))
            } catch (error) {
                socket.emit('auth error', {
                    success: false,
                    message: '登录已过期，请重新登录获取新 Token',
                });
            }
        });

        // 好友关系更新通知：好友请求、好友通过、好友拒绝
        socket.on('friendship update notification', (status, tid) => {
            const targetSocketId = findTargetSocketId(parseInt(tid))
            if (targetSocketId != null) {
                switch (status) {
                    case 0:
                        io.to(targetSocketId).emit('friendship add notification', message = '您有一个新的好友请求！')
                        break;
                    case 1:
                        io.to(targetSocketId).emit('friendship pass notification', message = '对方通过了你的好友请求！')
                        break;
                }
            } else {
                io.to(socket.id).emit('friendship offline notification', message = '目标用户当前不在线，无法进行消息推送！')
            }
        })

        // 私聊消息(一对一)：发送者 -> 接收者
        socket.on('private-chat', async (tid, message) => {
            const senderId = socketUserMap.get(socket.id); // 发送者ID
            const receiverId = parseInt(tid); // 接收者ID
            const minId = Math.min(senderId, receiverId); // 确保按顺序存储
            const maxId = Math.max(senderId, receiverId); // 确保按顺序存储
            const chatKey = `private:chat:${minId}:${maxId}`; // 私聊消息唯一 key       

            // 检查目标用户是否在线
            if (userSocketMap.has(receiverId)) {
                // 接收者：通知目标用户并接收消息
                io.to(findTargetSocketId(parseInt(tid))).emit('private-message', {
                    id: senderId,
                    message: message,
                    message_type: 'text',
                    created_at: new Date().getTime()
                })
                // 发送者：也需要收到发送的消息
                socket.emit('private-message-self', {
                    id: senderId,
                    message: message,
                    message_type: 'text',
                    created_at: new Date().getTime()
                })

                try {
                    // 存为 JSON 字符串到 Redis List（lpush）
                    await redis.lPush(chatKey, JSON.stringify({
                        id: senderId, // 发送者ID
                        message: message, // 发送的消息内容
                        message_type: 'text', // 消息类型：文本
                        created_at: new Date().getTime() // 发送时间
                    }))
                    // 可选：只保留最近 1000 条，防止内存爆炸
                    await redis.lTrim(chatKey, 0, 999);
                } catch (error) {
                    console.error('❌ 私聊消息存入 Redis 失败:', error);
                }
            } else {
                // 目标不在线，仍可存入 Redis（离线消息）
                try {
                    const minId = Math.min(senderId, receiverId); // 确保按顺序存储
                    const maxId = Math.max(senderId, receiverId); // 确保按顺序存储
                    const chatKey = `private:chat:${minId}:${maxId}`; // 私聊消息唯一 key
                    await redis.lPush(chatKey, JSON.stringify({
                        id: senderId, // 发送者ID
                        message: message, // 发送的消息内容
                        message_type: 'text', // 消息类型：文本
                        created_at: new Date().getTime() // 发送时间
                    }));
                    await redis.lTrim(chatKey, 0, 999); // 只保留最近 1000 条
                } catch (error) {
                    console.error('❌ 存储离线消息到 Redis 失败:', error);
                }
            }
        })

        // 群聊通知：群成员更新
        socket.on('group-notification', (members) => {
            // 通知：群聊中的所有成员
            members.forEach((item) => {
                io.to(findTargetSocketId(parseInt(item.uid))).emit('groupData-synchronization')
                io.to(socket.id).emit('groupData-synchronization')
            })
        })

        // 群聊消息(群聊)：发送者 -> 接收者
        socket.on('group-chat', async (groupInfo, message) => {
            const senderId = socketUserMap.get(socket.id); // 发送者ID
            const other_members = JSON.parse(groupInfo.members).filter((item) => item.uid != senderId) // 过滤出其他成员

            // 向群内的其他成员发送消息
            other_members.forEach((item) => {
                // 群聊消息：发送者 -> 接收者
                io.to(findTargetSocketId(parseInt(item.uid))).emit('group-message', {
                    uid: senderId, // 发送者ID
                    groupId: groupInfo.id, // 群聊ID
                    nickname: userDecodedMap.get(socket.id).nickname, // 发送者昵称
                    avatar: userDecodedMap.get(socket.id).avatar, // 发送者头像
                    message: message, // 发送的消息内容
                    message_type: 'text', // 消息类型：文本
                    created_at: new Date().getTime() // 发送时间
                })
            })

            // 群聊消息（发送者自己也需要手动消息）：发送者 -> 发送者
            socket.emit('group-message-self', {
                uid: senderId, // 发送者ID
                groupId: groupInfo.id, // 群聊ID
                nickname: userDecodedMap.get(socket.id).nickname, // 发送者昵称
                avatar: userDecodedMap.get(socket.id).avatar, // 发送者头像
                message: message, // 发送的消息内容
                message_type: 'text', // 消息类型：文本
                created_at: new Date().getTime() // 发送时间
            })

            try {
                const chatKey = `group:chat:${groupInfo.id}`; // 群聊消息唯一 key

                // 存为 JSON 字符串到 Redis List（lpush）
                await redis.lPush(chatKey, JSON.stringify({
                    id: senderId, // 发送者ID
                    nickname: userDecodedMap.get(socket.id).nickname, // 发送者昵称
                    avatar: userDecodedMap.get(socket.id).avatar, // 发送者头像
                    message: message, // 发送的消息内容
                    message_type: 'text', // 消息类型：文本
                    created_at: new Date().getTime() // 发送时间
                }))

                // 可选：只保留最近 1000 条，防止内存爆炸
                await redis.lTrim(chatKey, 0, 999);
            } catch (error) {
                console.error('❌ 群聊消息存入 Redis 失败:', error);
            }
        })

        // 好友在线状态 
        socket.on('target online status', (tid) => {
            if (userSocketMap.has((parseInt(tid)))) {
                socket.emit('online', '当前在线')
            } else {
                socket.emit('offline', '离线')
            }
        })

        // 发起视频通话
        socket.on('video-call-request', (tid) => {
            if (!tid) {
                return socket.emit('error', 'target user not found')
            }
            try {
                io.to(findTargetSocketId(parseInt(tid))).emit('video-call-receiver', {
                    uid: socketUserMap.get(socket.id),
                    nickname: userDecodedMap.get(socket.id).nickname,
                    avatar: userDecodedMap.get(socket.id).avatar,
                    direction: 'incoming'
                })
            } catch (error) {
                console.error('❌ 视频通话请求失败:', error);
            }
        })

        // 同意视频通话
        socket.on('video-call-accept', (tid) => {
            io.to(findTargetSocketId(parseInt(tid))).emit('video-call-accept', true)
        })

        // 视频通话ICE候选
        socket.on('video-call-sender-candidate', (tid, candidate) => {
            io.to(findTargetSocketId(parseInt(tid))).emit('video-call-receive-candidate', candidate)
        })

        // 视频通话Offer
        socket.on('video-call-sender-offer', (tid, offer) => {
            io.to(findTargetSocketId(parseInt(tid))).emit('video-call-receive-offer', offer)
        })

        // 视频通话Answer
        socket.on('video-call-sender-answer', (tid, answer) => {
            io.to(findTargetSocketId(parseInt(tid))).emit('video-call-receive-answer', answer)
        })

        // 视频通话结束
        socket.on('video-call-end', (tid) => {
            io.to(findTargetSocketId(parseInt(tid))).emit('video-call-end', '对方已挂断')
            socket.emit('video-call-end', '您已挂断')
        })

        // 断开连接
        socket.on('disconnect', () => {
            const uid = socketUserMap.get(socket.id)
            if (uid) {
                userSocketMap.delete(uid)
                socketUserMap.delete(socket.id)
            }
        });
    });
};